﻿using CommonModel.Field;
using CommonModel.Model;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static CommonModel.Model.DataTypeDll;
using static CommonModel.Util.Struct;

namespace CommonModel.Util
{
    public class Code
    {
        //命令码解析，其中300W/1000W是命令码解析，但是与其他常见的不同，需要通过参数判别
        public static Dictionary<string, Object> ByteParseViaCode(SchemaDocument doc, byte[] data, string DeviceModelType)
        {
            /*int currentCursor = 15; // data字节数组解析游标起始位置，剔除前面的15位ip等数据
            int currentParsedIndex = 0; // 解析后字段的顺序*/
            Dictionary<int, Object> schemaDictionary = doc.getFieldDictionary();//读取的XML模板的字段字典
            Dictionary<string, Object> parsedDataDictionary = new Dictionary<string, object>();//解析后的字典
            Dictionary<string, Object> dictDictionary = new Dictionary<string, Object>();//中介字典
            if (DeviceModelType == "M_300_1000")
            {
                dictDictionary = parseCodes300Or1000(data);
            }
            else
            {
                dictDictionary = parseCodes(data);
            }
            parseDictionary(schemaDictionary, dictDictionary, parsedDataDictionary/*,ref currentCursor,ref currentParsedIndex*/);//解析


            return parsedDataDictionary;
        }


        /**
            * 根据schemaDictionary解析字段<br/>0
            * 逐个对照解析字典进行命令码的解析<br/>
            *
            * @param schemaDictionary - 解析规则字典
            * @param dictDictionary   - 命令码与数据对照字典
            * @return
            */
        public static void parseDictionary(Dictionary<int, Object> schemaDictionary, Dictionary<string, Object> dictDictionary, Dictionary<string, Object> parsedDataDictionary/*,ref int currentCursor, ref int currentParsedIndex*/)
        {
            for (int i = 0; i < schemaDictionary.Count; i++)
            {
                Object schObj = schemaDictionary[i];

                /**
                    * 如果是普通的字段, 且不是字节位标识 bit 字段<br/>
                    */
                if (schObj is FieldSchema)
                {
                    FieldSchema schField = (FieldSchema)schObj;
                    parseField(schField, dictDictionary, parsedDataDictionary/*, ref currentCursor, ref currentParsedIndex*/);
                }
                /**
                 * 如果是字段集
                 */
                if (schObj is SchemaDictionary)
                {
                    //其中0x4000和0x7000是不在协议文档中的，要特别处理
                    SchemaDictionary subSchDictionary = (SchemaDictionary)schObj;
                    DataType datype = subSchDictionary.getType();
                    string paraCode = subSchDictionary.getCode();
                    int looper = 0;
                    string name = subSchDictionary.getName();
                    string code = subSchDictionary.getCode();
                    if(!(name.Equals("N0x4000")|| name.Equals("N0x7000"))&&dictDictionary.ContainsKey(code))
                    {
                        parsedDataDictionary.Add(name, new List<Dictionary<string, Object>>());
                    }
                    
                    if (dictDictionary.ContainsKey(paraCode))
                    {
                        switch (datype)
                        {
                            /**
                             * 位状态结构体, 低位在前高位在后
                             */
                            case DataType.BITARRAY:
                                looper = getLooper(subSchDictionary,parsedDataDictionary);
                                for(int counter = 0; counter < looper; counter++)
                                {
                                    ((List<Dictionary<string, Object>>)parsedDataDictionary[name]).Add(new Dictionary<string, object>());
                                    parseBitArray(dictDictionary, subSchDictionary, ((List<Dictionary<string, Object>>)(parsedDataDictionary)[name])[counter]/*, ref currentCursor, ref currentParsedIndex*/);
                                }
                                
                                break;
                            /**
                             * 结构体, loop循环结构体
                             */
                            case DataType.STRUCT:
                                parseCodeStruct(dictDictionary, subSchDictionary, parsedDataDictionary/*, ref currentCursor, ref currentParsedIndex*/);
                                break;
                            default:
                                break;
                        }
                    }
                    else
                    {
                        continue;
                    }

                }

            }
        }

        /**
	 * 解析成单独的字段
	 *
	 * @param schema
	 * @param dict
	 * @param parsedDictionary
	 */
        public static void parseField(FieldSchema schField, Dictionary<string, Object> dict, Dictionary<string, Object> parsedDataDictionary/*, ref int currentCursor, ref int currentParsedIndex*/)
        {
            string paraCode = schField.getCode();
            try
            {
                /**
				 * 从 dict 中取出对应的命令码的值作为待解析的值<br/>
				 */
                if (dict.ContainsKey(paraCode))
                // 如果在字典中找到, 则解析, 否则忽略
                {
                    CodeField codeField = (CodeField)dict[paraCode];
                    FieldData parField = new ParsedField();
                    string schName = schField.getName();
                    int len = schField.getSize();
                    parField.setName(schName);

                    /**
					 * 如果需要告警
					 */
                    if (schField.isAlarm())
                    {
                        parField.setAlarm(true);
                        parField.setAlarmName(schField.getAlarmName());
                        parField.setAlarmValue(schField.getAlarmValue());
                    }

                    DataType type = schField.getType();
                    byte[] datax = (byte[])codeField.getValue();

                    string value = "";

                    try
                    {
                        value = BytesParseToTypeString.ParseValue(type, datax);//开始解析
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("解析单独的字段出错，出错字段是：", paraCode, "出错问题是：", e);
                    }

                    parField.setValue(value);
                    /*currentParsedIndex++;
					currentCursor = currentCursor + len;*/
                    //parsedDataDictionary.Add(schName, parField);
                    parsedDataDictionary.Add(schName, value);
                }
                else
                {
                    return;
                }
            }
            catch (Exception e)
            {
                //String errMsg = String.format("解析字段 %-32s 失败!", paraCode);
                Console.WriteLine("待解析的字典中无对应待解析的参数码" + e);
            }
        }

        /**
		 * 解析成字节长度结构体，循环
		 *
		 * @param dict
		 * @param schema
		 * @param parsedMap
		 */
        public static void parseCodeStruct(Dictionary<String, Object> dictDictionary, SchemaDictionary subSchDictionary, Dictionary<string, Object> parsedDataDictionary/*, ref int currentCursor, ref int currentParsedIndex*/)
        {
            Dictionary<int, Object> subSchFieldDictionary = subSchDictionary.getFieldDictionary();
            string paraCode = subSchDictionary.getCode();
            string pname = subSchDictionary.getName();
            //int a = 0;
            //int b = 0;
            if (paraCode.Equals("0x4000") || paraCode.Equals("0x7000"))
            {
                List<Object> paravale = (List<Object>)dictDictionary[paraCode];//获取到待解析的list数据,list的集合是CodeField对象，待解析的所有字段是bit和uint8类型，所采用的解析方法都是ByteToUint8()

                if (paraCode.Equals("0x4000"))
                {
                    List<Object> newparavalue1 = new List<object>();
                    Dictionary<string, Object> dictarray = new Dictionary<string, object>();
                    List<Dictionary<string, Object>> listarray = new List<Dictionary<string, object>>();
                    //List<Object> newparavalue11 = new List<object>();
                    for (int i = 0; i < paravale.Count(); i++)
                    {            
                        CodeField codeField = (CodeField)paravale[i];
                        byte[] value = (byte[])codeField.getValue();//获取到值
                        string name = codeField.getCode();//获取到编号名
                        string newname = TransForm.ByteToUint8(value).ToString();
                        if (name.Equals("0x0400"))
                        {
                            //a++;
                            listarray = new List<Dictionary<string, object>>();//重置
                            dictarray= new Dictionary<string, object>();
                        }
                        dictarray.Add(name, newname);
                        
                        if (name.Equals("0x0406"))
                        {
                            listarray.Add(dictarray);
                            newparavalue1.Add(listarray);
                        }

                        //newparavalue1.Add(TransForm.ByteToUint8(value));
                    }

                    //int j = 0;//0400-0406共7个
                    //List<Object> c;//中间量
                    //for (int k = 0; k < a; k++)
                    //{
                    //    c = newparavalue1.Skip(j).Take(7).ToList();//take为每次取的数量，skip为跳过的数量。执行时take每次取0~9，skip跳过i项。
                    //    j += 7;
                    //    newparavalue11.Add(c);
                    //}
                    parsedDataDictionary.Add("N" + paraCode, newparavalue1);
                }

                if (paraCode.Equals("0x7000"))
                {
                    List<Object> newparavalue2 = new List<object>();
                    Dictionary<string, Object> dictarray = new Dictionary<string, object>();
                    List<Dictionary<string, Object>> listarray = new List<Dictionary<string, object>>();
                    //List<Object> newparavalue22 = new List<object>();
                    for (int i = 0; i < paravale.Count(); i++)
                    {
                        CodeField codeField = (CodeField)paravale[i];
                        byte[] value = (byte[])codeField.getValue();
                        string name = codeField.getCode();//获取到编号名
                        string newname = TransForm.ByteToUint8(value).ToString();
                        if (name.Equals("0x0700"))
                        {
                            //b++;
                            listarray = new List<Dictionary<string, object>>();//重置
                            dictarray = new Dictionary<string, object>();
                        }
                        dictarray.Add(name, newname);
                        
                        if (name.Equals("0x0704"))
                        {
                            listarray.Add(dictarray);
                            newparavalue2.Add(listarray);
                        }
                        //newparavalue2.Add(TransForm.ByteToUint8(value));
                    }
                    //int m = 0;//0700-0704共5个
                    //List<Object> d;//中间量
                    //for (int n = 0; n < b;n++)
                    //{
                    //    d = newparavalue2.Skip(m).Take(5).ToList();//take为每次取的数量，skip为跳过的数量。执行时take每次取0~9，skip跳过i项。
                    //    m += 5;
                    //    newparavalue22.Add(d);
                    //}
                    parsedDataDictionary.Add("N"+paraCode, newparavalue2);
                }
            }
            else
            { //即使type是struct,其实就是type=bitarray循环几次。
                CodeField codeField = (CodeField)dictDictionary[paraCode];
                // 如果在字典中找到, 则解析, 否则忽略
                if (null == codeField)
                {
                    return;
                }
                int looper = getLooper_code(subSchDictionary, parsedDataDictionary);
                for (int counter = 0; counter < looper; counter++)
                {
                    try
                    {
                        ((List<Dictionary<string, Object>>)(parsedDataDictionary)[pname]).Add(new Dictionary<string, object>());
                        parseBitArray(dictDictionary, subSchDictionary, ((List<Dictionary<string, Object>>)(parsedDataDictionary)[pname])[counter]/*, ref currentCursor, ref currentParsedIndex*/);

                        //parseDictionary(subSchFieldDictionary, dict, ((List<Dictionary<string, Object>>)(parsedDataDictionary)[pname])[counter]/*, ref currentCursor, ref currentParsedIndex*/);

                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("解析字节结构循环体出错" + e);
                    }
                }
            }


        }

        /**
		 * 获取结构体数组的长度
		 *
		 * @param schMap - 结构体解析字典
		 * @return - 字典中实际的loop属性值, 即数组个数
		 */
        public static int getLooper_code(SchemaDictionary schDictionary, Dictionary<string, Object> parsedDataDictionary)
        {
            // TODO Auto-generated method stub
            string loopStr = schDictionary.getLoop();
            string loopValueStr = "";
            int loop = 1;
            if (loopStr == "0")
            {
                return -1;//表示不解析该字段
            }
            if (null == loopStr || loopStr.Equals(""))
            {
                loopStr = "1";
            }
            //正则判断是否是数字
            string regex = "^(-?[0-9]*[.]*[0-9]{0,3})$";
            /**
             * 如果是关联字段获取数组个数
             */
            if (Regex.IsMatch(loopStr, regex))
            {
                loopValueStr = loopStr;
                loop = Convert.ToInt32(loopValueStr);
            }
            else
            {
                Console.WriteLine(parsedDataDictionary);
                // 从已经解析的parsedDataDictionary中取出对应的值
                loopValueStr = parsedDataDictionary[loopStr].ToString();

                loop = Convert.ToInt32(loopValueStr);
            }

            return loop;
        }

        /**
		 * 解析成字节位结构体<br/>
		 * @param dict
		 * @param code
		 * @param schema
		 * @param parsedMap
		 */
        public static void parseBitArray(Dictionary<string, Object> dict, SchemaDictionary subSchDictionary, Dictionary<string, Object> parsedDataDictionary/*, ref int currentCursor, ref int currentParsedIndex*/)
        {
            string paraCode = subSchDictionary.getCode();
            CodeField codeField = (CodeField)dict[paraCode];
            // 如果在字典中找到, 则解析, 否则忽略
            if (null != codeField)
            {
                byte[] datax = (byte[])codeField.getValue();
                byte[] bitArray = TransForm.bytesToBitArray(datax);
                Dictionary<int, Object> schFieldDictionary = subSchDictionary.getFieldDictionary();
                // 设置字节位解析位置
                int cursor = 0;

                for (int i = 0; i < schFieldDictionary.Count; i++)
                {
                    FieldSchema fieldSch = (FieldSchema)schFieldDictionary[i];

                    // 根据 size 值截取字节位
                    int size = fieldSch.getSize();
                    int newCursor = cursor + size;

                    if (newCursor > bitArray.Length)
                    {
                        // 超出字节位长度, 则继续
                        continue;
                    }

                    FieldData parField = new ParsedField();
                    string name = fieldSch.getName();
                    parField.setName(name);

                    /**
                        * 如果需要告警
                        */
                    if (fieldSch.isAlarm())
                    {
                        parField.setAlarm(true);
                        parField.setAlarmName(fieldSch.getAlarmName());
                        parField.setAlarmValue(fieldSch.getAlarmValue());
                    }

                    StringBuilder value = new StringBuilder();

                    for (int idx = 0; idx < size; idx++)
                    {
                        // 一位一位进行转换, 然后再组合成字符串
                        byte[] data = new byte[1];
                        data[idx] = bitArray[cursor + idx];
                        try
                        {
                            value.Append(BytesParseToTypeString.ParseValue(DataType.BYTE, data));
                        }
                        catch (Exception e)
                        {
                            // TODO Auto-generated catch block
                            Console.WriteLine("解析bitarray出错" + e);
                        }
                    }
                    cursor = cursor + size;
                    parField.setValue(value.ToString());
                    parsedDataDictionary.Add(name, value.ToString());
                }
            }
        }

        /**
            * 对 bitarray结构进行解析<br/>
            * 2020/11/16 likangfu 增加子字段为多个字节位组合的情况解析 <br/>
            * @param schMap:    解析字典
            * @param parsedSeg: 解析段
            * @param data:      数据
            * @return
            */
        public static void parseBitArrayDictionary(SchemaDictionary schDictionary, /*SegmentData parsedSeg, */byte[] data)
        {
            // TODO Auto-generated method stub
            byte[] bitArray = TransForm.bytesToBitArray(data);
            Dictionary<int, Object> schFieldDictionary = schDictionary.getFieldDictionary();
            Dictionary<string, Object> parsedDataDictionary = new Dictionary<string, Object>();
            // 设置字节位解析位置
            int cursor = 0;

            for (int i = 0; i < schFieldDictionary.Count; i++)
            {
                FieldSchema fieldSch = (FieldSchema)schFieldDictionary[i];

                // 根据 size 值截取字节位
                int size = fieldSch.getSize();
                int newCursor = cursor + size;

                if (newCursor > bitArray.Length)
                {
                    // 超出字节位长度, 则继续
                    continue;
                }

                FieldData parField = new ParsedField();
                string name = fieldSch.getName();
                parField.setName(name);

                /**
                    * 如果需要告警
                    */
                if (fieldSch.isAlarm())
                {
                    parField.setAlarm(true);
                    parField.setAlarmName(fieldSch.getAlarmName());
                    parField.setAlarmValue(fieldSch.getAlarmValue());
                }

                StringBuilder value = new StringBuilder();

                for (int idx = 0; idx < size; idx++)
                {
                    // 一位一位进行转换, 然后再组合成字符串
                    byte[] datax = new byte[1];
                    datax[idx] = bitArray[cursor + idx];
                    try
                    {
                        value.Append(BytesParseToTypeString.ParseValue(DataType.BYTE, datax));
                    }
                    catch (Exception e)
                    {
                        // TODO Auto-generated catch block
                        Console.WriteLine("解析bitarray出错" + e);
                    }
                }

                cursor = cursor + size;

                parField.setValue(value.ToString());
                //parsedDataDictionary.Add(i, parField);
                parsedDataDictionary.Add(name, value.ToString());

            }
            //parsedSeg.setFieldDictionary(parsedDataDictionary);
        }

        /**
         * 将数据解析到命令码字典对照表中 通用类型<br/>
         * 
         * @param data
         * @return
         */
        public static Dictionary<string, Object> parseCodes(byte[] data)
        {
            // 设置开始游标
            int currentCursor = 43;//去掉程序前面加的15位信息,28位帧头信息
            Dictionary<string, Object> fieldDictionary = new Dictionary<string, Object>();
            // 设备ID
            byte[] devidbyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField idCodeField = new CodeField();
            idCodeField.setCode("devid");
            idCodeField.setValue(devidbyte);
            fieldDictionary.Add("devid", idCodeField);

            // 功能码
            byte[] funCodebyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField funCodeField = new CodeField();
            funCodeField.setCode("funcode");
            funCodeField.setValue(funCodebyte);
            fieldDictionary.Add("funcode", funCodeField);

            // 数据长度
            byte[] datlbyte = data.Skip(currentCursor).Take(2).ToArray();
            currentCursor = currentCursor + 2;
            CodeField lenField = new CodeField();
            lenField.setCode("datalength");
            lenField.setValue(datlbyte);
            fieldDictionary.Add("datalength", lenField);

            //参数有三个部分：2字节的参数序号，1字节的参数长度，参数长度字节的参数值
            while (currentCursor < data.Length - 2)
            {
                byte[] parabyte = data.Skip(currentCursor).Take(2).ToArray();//参数序号
                currentCursor = currentCursor + 2;
                string paracode = TransForm.ByteToHexString(parabyte);

                byte[] paraLbyte = data.Skip(currentCursor).Take(1).ToArray();//参数长度
                currentCursor = currentCursor + 1;
                int paraLen = TransForm.ByteToUint8(paraLbyte);

                byte[] paravalue = data.Skip(currentCursor).Take(paraLen).ToArray(); //参数值
                currentCursor = currentCursor + paraLen;
                CodeField codeField = new CodeField();
                codeField.setCode(paracode);
                codeField.setValue(paravalue);
                fieldDictionary.Add(paracode, codeField);
            }
            return fieldDictionary;
        }


        /**
            * 将数据解析到命令码字典对照表中 300/1000W数字电视发射机类型<br/>
            * 
            * @param data
            * @return
            */
        public static Dictionary<string, Object> parseCodes300Or1000(byte[] data)
        {
            // 设置开始游标
            int currentCursor = 15;
            //Dictionary<string, CodeField> fieldDictionary = new Dictionary<string, CodeField>();
            Dictionary<string, Object> fieldDictionary = new Dictionary<string, Object>();
            // 起始字
            byte[] startFlagbyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField startFlagField = new CodeField();
            startFlagField.setCode("startflag");
            startFlagField.setValue(startFlagbyte);
            fieldDictionary.Add("startflag", startFlagField);

            // 设备地址
            byte[] devidbyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField idCodeField = new CodeField();
            idCodeField.setCode("devid");
            idCodeField.setValue(devidbyte);
            fieldDictionary.Add("devid", idCodeField);

            // 指令码
            byte[] funCodebyte = data.Skip(currentCursor).Take(1).ToArray();
            currentCursor = currentCursor + 1;
            CodeField funCodeField = new CodeField();
            funCodeField.setCode("funcode");
            funCodeField.setValue(funCodebyte);
            fieldDictionary.Add("funcode", funCodeField);

            // 数据长度
            byte[] datlbyte = data.Skip(currentCursor).Take(2).ToArray();
            currentCursor = currentCursor + 2;
            CodeField lenField = new CodeField();
            lenField.setCode("datalength");
            lenField.setValue(datlbyte);
            fieldDictionary.Add("datalength", lenField);
            //int i = 1;//功放
            //int j = 1;//直流稳压

            //Dictionary<string, Object> listdict = new Dictionary<string, Object>();
            //Dictionary<string, Object> listdict2 = new Dictionary<string, Object>();
            List<Object> list1 = new List<object>();
            List<Object> list2 = new List<object>();
            while (currentCursor < data.Length - 2)
            {
                byte[] parabyte = data.Skip(currentCursor).Take(2).ToArray();//参数码
                currentCursor = currentCursor + 2;
                string paracode = TransForm.ByteToHexString(parabyte);

                byte[] paraLbyte = data.Skip(currentCursor).Take(2).ToArray();//参数长度
                currentCursor = currentCursor + 2;
                int paraLen = TransForm.ByteToUint8(paraLbyte);

                byte[] paravalue = data.Skip(currentCursor).Take(paraLen).ToArray(); //参数值
                currentCursor = currentCursor + paraLen;
                CodeField codeField = new CodeField();
                codeField.setCode(paracode);
                codeField.setValue(paravalue);

                if (paracode.Equals("0x0400") || paracode.Equals("0x0401") || paracode.Equals("0x0402") || paracode.Equals("0x0403") || paracode.Equals("0x0404") || paracode.Equals("0x0405") || paracode.Equals("0x0406"))
                {
                    list1.Add(codeField);
                    continue;//不加入fieldDictionary字典
                }

                if (paracode.Equals("0x0700") || paracode.Equals("0x0701") || paracode.Equals("0x0702") || paracode.Equals("0x0703") || paracode.Equals("0x0704"))
                {
                    list2.Add(codeField);
                    continue;//不加入fieldDictionary字典
                }

                //判断字典中是否已经存在相同的参数码且值相同,这里要把处理的结果加入日志
                if (fieldDictionary.ContainsKey(paracode))
                {
                    //IP放最前面4字节
                    byte[] ip = data.Skip(0).Take(4).ToArray();
                    Console.WriteLine("有重复");
                    //写入日志并调过该参数
                    string svalue = TransForm.BytesToFormatIp(ip) + ":" + paracode + "重复";
                    string log_path2 = Environment.CurrentDirectory + @"/Log/" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt";
                    FileStream fs = new FileStream(log_path2, FileMode.Append, FileAccess.Write);
                    StreamWriter swrite = new StreamWriter(fs, Encoding.Default);
                    swrite.Write(svalue);
                    swrite.WriteLine("\r\n");
                    swrite.Flush();
                    swrite.Close();
                    continue;

                }

                fieldDictionary.Add(paracode, codeField);
            }
            fieldDictionary.Add("0x4000", list1);
            fieldDictionary.Add("0x7000", list2);
            return fieldDictionary;
        }
    }
}
